﻿using System;
using System.Collections.Generic;
using System.Data.Linq;
using System.Linq;
using MB.TheBeerHouse.DAL;

namespace MB.TheBeerHouse.BLL.Articles
{
   public partial class tbh_Article : BaseArticleEntity
   {
      //******************************      
      // Public Properties
      //******************************

      public double AverageRating
      {
         get
         {
            if (this.Votes >= 1)
               return ((double)this.TotalRating / (double)this.Votes);
            else
               return 0.0;
         }
      }

      public string Location
      {
         get
         {
            string location = this.City.Split(';')[0];
            if (this.State.Length > 0)
            {
               if (location.Length > 0)
                  location += ", ";
               location += this.State.Split(';')[0];
            }
            if (this.Country.Length > 0)
            {
               if (location.Length > 0)
                  location += ", ";
               location += this.Country;
            }
            return location;
         }
      }

      public bool Published
      {
         get
         {
            return (this.Approved && this.Listed &&
               this.ReleaseDate <= DateTime.Now &&
               this.ExpireDate > DateTime.Now);
         }
      }

      //******************************      
      // Public Methods
      //******************************

      public static IEnumerable<tbh_Article_NoBody> GetArticles(bool publishedOnly, int categoryID,
         int startRowIndex, int maximumRows)
      {
         List<tbh_Article_NoBody> articles;

         if (publishedOnly)
         {
            if (categoryID > 0)
               articles = GetPublishedArticlesInCategoryQuery(categoryID).Skip(startRowIndex).Take(maximumRows).ToList();
            else
               articles = GetPublishedArticlesQuery().Skip(startRowIndex).Take(maximumRows).ToList();
         }
         else
         {
            if (categoryID > 0)
               articles = GetArticlesInCategoryQuery(categoryID).Skip(startRowIndex).Take(maximumRows).ToList();
            else
               articles = GetArticlesQuery().Skip(startRowIndex).Take(maximumRows).ToList();
         }         

         sharedContext.Dispose();
         return articles;
      }

      public static int GetArticleCount(bool publishedOnly, int categoryID)
      {
         int articleCount;

         using (ArticlesDataContext context = GetContext())
         {
            if (publishedOnly)
            {
               if (categoryID > 0)
                  articleCount = context.tbh_Articles
                     .Where(a => a.Approved && a.Listed &&
                        a.ReleaseDate <= DateTime.Now && a.ExpireDate > DateTime.Now &&
                        a.CategoryID == categoryID)
                        .Count();
               else
                  articleCount = context.tbh_Articles
                     .Where(a => a.Approved && a.Listed &&
                        a.ReleaseDate <= DateTime.Now && a.ExpireDate > DateTime.Now)
                        .Count();
            }
            else
            {
               if (categoryID > 0)
                  articleCount = context.tbh_Articles.Where(a => a.CategoryID == categoryID).Count();
               else
                  articleCount = context.tbh_Articles.Count();
            }
         }

         return articleCount;
      }

      public static tbh_Article GetArticleByID(int articleID)
      {
         using (ArticlesDataContext context = GetContext())
         {
            context.DeferredLoadingEnabled = false;
            DataLoadOptions loadOptions = new DataLoadOptions();
            loadOptions.LoadWith<tbh_Article>(a => a.tbh_Category);
            context.LoadOptions = loadOptions;

            return context.tbh_Articles.Where(a => a.ArticleID == articleID).SingleOrDefault();
         }
      }

      public static void InsertArticle(tbh_Article article)
      {
         bool canApprove = CurrentUser.IsInRole("Administrators") || CurrentUser.IsInRole("Editors");
         if (!canApprove)
            article.Approved = false;

         article.Title = ConvertNullToEmptyString(article.Title);
         article.Abstract = ConvertNullToEmptyString(article.Abstract);
         article.Body = ConvertNullToEmptyString(article.Body);
         article.Country = ConvertNullToEmptyString(article.Country);
         article.State = ConvertNullToEmptyString(article.State);
         article.City = ConvertNullToEmptyString(article.City);
         article.AddedDate = DateTime.Now;
         article.AddedBy = CurrentUserName;

         if (article.ReleaseDate == null)
            article.ReleaseDate = DateTime.Now.Date;
         if (article.ExpireDate == null)
            article.ExpireDate = DateTime.MaxValue.Date;

         using (ArticlesDataContext context = GetContext())
         {
            context.tbh_Articles.InsertOnSubmit(article);
            context.SubmitChanges();
         }
      }

      public static void UpdateArticle(tbh_Article changedArticle)
      {
         changedArticle.Title = ConvertNullToEmptyString(changedArticle.Title);
         changedArticle.Abstract = ConvertNullToEmptyString(changedArticle.Abstract);
         changedArticle.Body = ConvertNullToEmptyString(changedArticle.Body);
         changedArticle.Country = ConvertNullToEmptyString(changedArticle.Country);
         changedArticle.State = ConvertNullToEmptyString(changedArticle.State);
         changedArticle.City = ConvertNullToEmptyString(changedArticle.City);

         if (changedArticle.ReleaseDate == null)
            changedArticle.ReleaseDate = DateTime.Now.Date;
         if (changedArticle.ExpireDate == null)
            changedArticle.ExpireDate = DateTime.MaxValue.Date;

         using (ArticlesDataContext context = GetContext())
         {
            context.tbh_Articles.Attach(changedArticle, true);
            context.SubmitChanges();
         }
      }

      public static void DeleteArticle(tbh_Article article)
      {
         using (ArticlesDataContext context = GetContext())
         {
            context.tbh_Articles.Attach(article);
            context.tbh_Articles.DeleteOnSubmit(article);
            context.SubmitChanges();
         }
         new RecordDeletedEvent("article", article.ArticleID, null).Raise();
      }

      public static void DeleteArticle(int articleID)
      {
         using (ArticlesDataContext context = GetContext())
         {
            tbh_Article article = context.tbh_Articles.Where(a => a.ArticleID == articleID).SingleOrDefault();
            context.tbh_Articles.DeleteOnSubmit(article);
            context.SubmitChanges();
         }
         new RecordDeletedEvent("article", articleID, null).Raise();
      }

      public void IncrementViewCount()
      {
         using (ArticlesDataContext context = GetContext())
         {
            tbh_Article article = context.tbh_Articles.Where(a => a.ArticleID == this.ArticleID).SingleOrDefault();
            article.ViewCount++;
            context.SubmitChanges();
         }
      }

      public static void RateArticle(int articleID, int userRating)
      {
         using (ArticlesDataContext context = GetContext())
         {
            tbh_Article article = context.tbh_Articles.Where(a => a.ArticleID == articleID).SingleOrDefault();
            article.Votes++;
            article.TotalRating += userRating;
            context.SubmitChanges();
         }
      }

      public static void ApproveArticle(int articleID)
      {
         using (ArticlesDataContext context = GetContext())
         {
            tbh_Article article = context.tbh_Articles.Where(a => a.ArticleID == articleID).SingleOrDefault();
            article.Approved = true;
            context.SubmitChanges();
         }
      }

      //******************************      
      // Private Methods
      //******************************
      
      private static ArticlesDataContext sharedContext;

      private static IOrderedQueryable<tbh_Article_NoBody> GetArticlesQuery()
      {
         sharedContext = GetContext();

         sharedContext.DeferredLoadingEnabled = false;
         DataLoadOptions loadOptions = new DataLoadOptions();
         loadOptions.LoadWith<tbh_Article>(a => a.tbh_Category);
         sharedContext.LoadOptions = loadOptions;

         return sharedContext.tbh_Articles.Select(a => new tbh_Article_NoBody
         {
            ArticleID = a.ArticleID,
            AddedDate = a.AddedDate,
            AddedBy = a.AddedBy,
            CategoryID = a.CategoryID,
            tbh_Category = a.tbh_Category,
            Title = a.Title,
            Abstract = a.Abstract,
            Country = a.Country,
            State = a.State,
            City = a.City,
            ReleaseDate = a.ReleaseDate,
            ExpireDate = a.ExpireDate,
            Approved = a.Approved,
            Listed = a.Listed,
            CommentsEnabled = a.CommentsEnabled,
            OnlyForMembers = a.OnlyForMembers,
            ViewCount = a.ViewCount,
            Votes = a.Votes,
            TotalRating = a.TotalRating,
            Version = a.Version
         }).OrderByDescending(a => a.ReleaseDate);
      }

      private static IQueryable<tbh_Article_NoBody> GetPublishedArticlesQuery()
      {
         return GetArticlesQuery().Where(a => a.Approved && a.Listed &&
            a.ReleaseDate <= DateTime.Now && a.ExpireDate > DateTime.Now);
      }

      private static IQueryable<tbh_Article_NoBody> GetArticlesInCategoryQuery(int categoryID)
      {
         return GetArticlesQuery().Where(a => a.CategoryID == categoryID);
      }

      private static IQueryable<tbh_Article_NoBody> GetPublishedArticlesInCategoryQuery(int categoryID)
      {
         return GetPublishedArticlesQuery().Where(a => a.CategoryID == categoryID);
      }
   }

   public class tbh_Article_NoBody : tbh_Article { }
}
